<!--
 * @Description: 
 * @Version: 2.0
 * @Autor: zhangjx
 * @Date: 2023-03-07 16:09:05
 * @LastEditors: uphldjx 1373577124@qq.com
 * @LastEditTime: 2024-08-01 18:57:00
-->
<template>
  <div class="upload-wrapper">
    <el-upload :key="uploadKey" ref="upload" class="avatar-uploader" :auto-upload="autoUpload" :disabled="onlyReady" :multiple="multiple" :limit="limit"
      v-model:file-list="fileList" :list-type="listType" action="" :http-request="onHttpRequest" :on-change="onFileChange"
      :show-file-list="showFileList" :on-preview="handleOnPreview" :before-upload="beforeUpload"
      :before-remove="beforeRemove" :on-exceed="handleExceed">
      <el-button :text="true" v-if="['text'].includes(listType)" type="primary">
        <el-icon>
          <Upload />
        </el-icon>
        点击上传
      </el-button>
      <template v-else>
        <PreviewImg v-if="imageUrl && !showFileList" :onlyReady="onlyReady" :showFileList="showFileList" :key="imageUrl" :src="imageUrl" class="avatar" @delete="handleDelete"></PreviewImg>
        <!-- <img v-if="imageUrl && !showFileList" :src="imageUrl" class="avatar" /> -->
        <el-icon v-else class="avatar-uploader-icon">
          <Plus />
        </el-icon>
      </template>
      <template #tip>
        <div class="el-upload__tip">{{ tip }} {{ uploadTip }}</div>
        <el-progress :text-inside="true" v-show="percent > 0" :stroke-width="20" :percentage="percent" />
      </template>
      <template v-slot:file="{file}">
        <PreviewImg :src="file.url" :disabled="disabled"  :onlyReady="onlyReady" :showFileList="showFileList" class="upload-preview-img" @delete="handleDelete"></PreviewImg>
      </template>
    </el-upload>

    <el-dialog v-model="dialogVisible" width="45%">
      <img w-full :src="imageUrl" alt="Preview Image" style="width: 100%" />
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { Upload } from '@element-plus/icons-vue'
import apiMod from '@/apiMod'
import PreviewImg from './PreviewImg/index.vue'
import { DeleteObsFile } from '@/utils/util'

import type {
  UploadInstance,
  UploadProps,
  UploadRawFile,
  UploadUserFile
} from 'element-plus'

const upload = ref<UploadInstance>()

type Props = {
  modelValue?: string | string[]
  listType?: 'text' | 'picture' | 'picture-card'
  showFileList?: boolean
  name?: string
  fileType?: string
  fileSize?: number
  tip?: string
  uploadTip?: string
  limit?: number
  autoUpload?: boolean
  multiple?: boolean
  dataType?: string
  EventChange?: Function
  formParamName?:string
  apiName?:string
  disabled?:boolean
  onlyReady?:boolean
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  listType: 'picture',
  showFileList: true,
  name: 'uploadFile',
  fileType: 'image/jpg,image/jpeg,image/gif,image/png,image/webp,image/tiff',
  fileSize: 20,
  uploadTip: '上传文件',
  limit: 9,
  multiple: false,
  autoUpload: true,
  dataType: 'string',
  EventChange: null,
  formParamName:'uploadFile',
  apiName:'uploadFile',
  disabled:false,
  onlyReady:false
})

const emit = defineEmits(['update:modelValue', 'change'])

const dialogVisible = ref(false)
const percent = ref(0)
const fileList = ref<UploadUserFile[]>([])
const imageUrl = ref('')
let fileDataList = ref([])
const getFileObj = (url, fileName?: string) => {
  if (url) {
    const name = decodeURIComponent(url).split('/').slice(-1)[0]
    return {
      url: url,
      name: fileName ? fileName : name
    }
  }
}

const onFileChange = async (file) => {
  console.log(file, 'change')
}
const onHttpRequest = async (options) => {
  const form = new FormData()
  form.append(props.formParamName, options.file)
  const data = await apiMod[props.apiName](form, (progressEvent) => {
    percent.value = Number(
      ((progressEvent.loaded / progressEvent.total) * 100).toFixed(1)
    )
  })
  if (data.code == 0 && props.listType == 'picture') {
    imageUrl.value = data.data
  }
  if (props.EventChange) props.EventChange('change', data)

  if (data.code == 0 && data.data) {
    const tempObj =getFileObj(data.data, options.file.name)
    if (fileDataList.value.length <= props.limit) {
      if (props.limit == 1 && !props.multiple) {
        fileDataList.value = [tempObj]
      } else {
        fileDataList.value.push(tempObj)
      }
    }
    updateData()
  }
}


const handleExceed: UploadProps['onExceed'] = (files) => {
  console.log('onExceed', '文件上传超出限制')
  if (props.limit == 1 && !props.multiple) {
    upload.value!.clearFiles()
    const file = files[0] as UploadRawFile
    file.uid = new Date().getTime()
    upload.value!.handleStart(file)
    upload.value!.submit()
  } else {
    ElMessage.warning(`只允许上传 ${props.limit} 个`)
  }
}
const handleOnPreview: UploadProps['onPreview'] = (uploadFile) => {
  if (props.listType !== 'text') {
    imageUrl.value = uploadFile.url!
    dialogVisible.value = true
  }
}

const updateData = () => {
  let data = fileDataList.value.map((item) => item.url)
  if (props.dataType == 'string') {
    emit('update:modelValue', data.join(','))
  } else {
    emit(
      'update:modelValue', data
    )
  }
  emit('change', fileDataList.value)
}

const beforeRemove: UploadProps['beforeRemove'] = (uploadFiles: any) => {
  percent.value  = 0
  setTimeout(() => {
    updateData()
  }, 200)
  return true
}
let uploadKey = ref(0)
const handleDelete = async(src)=> {
  
  fileDataList.value = fileDataList.value.filter(item=>item.url !=src)
  fileList.value = fileDataList.value
  percent.value  = 0
  await DeleteObsFile(src)
  if(!props.showFileList && !props.multiple) {
    imageUrl.value=''
  }
  uploadKey.value++
  setTimeout(() => {
    updateData()
  }, 200)
}

const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
  if (!props.fileType.split(',').includes(rawFile.type)) {
    ElMessage.error('上传格式不支持')
    return false
  } else if (rawFile.size / 1024 / 1024 > props.fileSize) {
    ElMessage.error(`上传文件不能超过 ${props.fileSize}MB!`)
    return false
  } else if (props.limit < fileDataList.value.length) {
    ElMessage.error(`最多上传${props.limit}个`)
    return false
  } else {
    return true
  }
}

watch(
  () => props.modelValue,
  (val) => {
    if (val && typeof val == 'string') {
      const formateArr:any = val.split(',').map((url) => {
        const tempObj = getFileObj(url)
        return tempObj
      })
      if (props.limit == 1 && formateArr.length > 1) {
        fileList.value = [formateArr[0]]
      } else {
        fileList.value = formateArr
      }
      if (!['text'].includes(props.listType) && !props.showFileList) {
        imageUrl.value = val
      }
    }else {
      fileList.value = []
    }
    fileDataList.value = fileList.value
  },
  {
    immediate: true
  }
)
</script>
<style lang="scss">
.avatar-uploader .el-upload--picture,
.el-upload--picture-card {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
  width: vw(120);
  height: vw(120);
}

.el-upload-list--picture-card .el-upload-list__item {
  width: vw(120);
  height: vw(120);
}

.avatar-uploader .avatar {
  width: 100%;
  height: 100%;
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}
.upload-preview-img {
  width: vw(120);
  height: vw(120);
}
.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: vw(120);
  height: vw(120);
  text-align: center;
}
</style>